#pragma once
#include<iostream>
#include<string>
#include<pthread.h>
#include <stdio.h>
#include<unistd.h>
#include <functional>
#include<cassert>

// 首先我们需要什么 ， 名字 ，id ，需要的执行的函数, 还有线程属性可以包括线程的堆栈大小、调度策略、分离状态等。

class Thread;

//上下文,当成一个大号的结构体
class Context
{
public:
    Thread *_this;
    void *_args;
public:
    Context():_this(nullptr), _args(nullptr)
    {}
    ~Context()
    {}
};


class Thread
{
public:
    // 这里就是申明了一种函数类型
    typedef std::function<void*(void*)> func_t;
    const int num = 1024;
public:
    Thread(func_t func, void *args = nullptr, int number = 0)
    :_func(func)
    ,_args(args)
    {
        char buffer[num];
        snprintf(buffer, sizeof buffer,"thread-%d",number);
        _name = buffer;

        Context* ctx = new Context();
        ctx->_this=this;
        ctx->_args =_args;

        int n = pthread_create(&_tid, nullptr, start_routine, ctx);
        assert(n == 0); //编译debug的方式发布的时候存在，release方式发布，assert就不存在了，n就是一个定义了，但是没有被使用的变量
        // 在有些编译器下会有warning
        (void)n;
    }

    static void* start_routine(void*args)
    {
        Context *ctx = static_cast<Context *>(args);
        void *ret = ctx->_this->run(ctx->_args);
        delete ctx;
        return ret;
    }

    void join()
    {
        int n = pthread_join(_tid, nullptr);
        assert(n == 0);
        (void)n;
    }

    void *run(void *args)
    {
        return _func(args);
    }

    ~Thread()
    {
        // do nothing
    }
private:
    std::string _name; // 线程名字
    pthread_t _tid;   // 线程id
    void* _args; // 这个其实是pthread_create 函数的const pthread_attr_t attr属性 。
                 // 如果传入 NULL，线程将使用默认属性创建。线程属性可以包括线程的堆栈大小、调度策略、分离状态等。
    func_t _func; // 执行的任务函数
};